 /* 高级I/O（文件） */

/* poll() I/O多路复用 */
/* 与非阻塞I/O轮询方式相比，CPU使用率大大降低 */
// #include <stdio.h> 
// #include <stdlib.h> 
// #include <sys/types.h> 
// #include <sys/stat.h> 
// #include <fcntl.h> 
// #include <unistd.h> 
// #include <sys/select.h> 
// #include <poll.h>

// #define MOUSE       "/dev/input/event2" 

// int main(void) 
// { 
//     char buf[100];
//     struct pollfd fds[2]; 
//     int fd, ret = 0, flag; 
//     int loops = 5; 
 
//     /* 打开鼠标设备文件 */ 
//     fd = open(MOUSE, O_RDONLY | O_NONBLOCK); 
//     if (-1 == fd) { 
//         perror("open error"); 
//         exit(-1); 
//     } 
 
//     /* 将键盘设置为非阻塞方式 */ 
//     flag = fcntl(0, F_GETFL);   //先获取原来的flag 
//     flag |= O_NONBLOCK;         //将O_NONBLOCK标准添加到flag 
//     fcntl(0, F_SETFL, flag);    //重新设置flag

//      /* 同时读取键盘和鼠标 */ 
//     fds[0].fd = 0;          //键盘
//     fds[0].events = POLLIN; //只关心数据可读 
//     fds[0].revents = 0; 
//     fds[1].fd = fd;         //鼠标
//     fds[1].events = POLLIN; //只关心数据可读 
//     fds[1].revents = 0; 
 
//     /* 同时读取键盘和鼠标 */ 
//     while (loops--) { 

//         ret = poll(fds, 2, -1); //无限阻塞
//         if (0 > ret) { 
//             perror("select error"); 
//             close(fd);
//             exit(-1);
//         } 
//         else if (0 == ret) { 
//             fprintf(stderr, "select timeout.\n"); 
//             continue; 
//         } 

//         /* 检查键盘是否为就绪态 */ 
//         if(fds[0].revents & POLLIN) { 
//             ret = read(0, buf, sizeof(buf)); 
//             if (0 < ret) 
//                 printf("键盘: 成功读取<%d>个字节数据\n", ret); 
//         } 
//         /* 检查鼠标是否为就绪态 */ 
//         if(fds[1].revents & POLLIN) { 
//             ret = read(fd, buf, sizeof(buf)); 
//             if (0 < ret) 
//                 printf("鼠标: 成功读取<%d>个字节数据\n", ret); 
//         }
//     }
    
//     close(fd);
//     exit(0); 
// } 


// /* 异步I/0 -- 信号驱动I/O */
// #define _GNU_SOURCE  //在源文件开头定义_GNU_SOURCE宏 

// #include <stdio.h> 
// #include <stdlib.h> 
// #include <sys/types.h> 
// #include <sys/stat.h> 
// #include <fcntl.h> 
// #include <unistd.h> 
// #include <signal.h> 

// #define MOUSE       "/dev/input/event2" 
// static int fd;

// static void sig_handler(int sig,siginfo_t *info,void *context)
// {
//     static int loops = 5;   //static修饰，只初始化一次
//     char buff[100] = {0};
//     int ret;

//     if(SIGRTMIN != sig) {
//         return ;
//     }
    
//     if(POLL_IN == info->si_code) {
//         ret = read(fd, buff, sizeof(buff)); 
//         if (0 < ret) 
//             printf("鼠标: 成功读取<%d>个字节数据\n", ret);
//         loops--;
//         if(0 >= loops) {    //轮询结束，正常退出
//             close(fd);
//             exit(0);
//         }
//     }
// }

// int main(void) 
// { 
//     int flag;
//     struct sigaction sig; 
 
//     /* 打开鼠标设备文件 */ 
//     fd = open(MOUSE, O_RDONLY | O_NONBLOCK); 
//     if (-1 == fd) { 
//         perror("open error"); 
//         exit(-1); 
//     } 
//     /* 使能异步I/O */ 
//     flag = fcntl(fd, F_GETFL);   //先获取原来的flag 
//     flag |= O_ASYNC;            //将O_ASYNC标志添加到flag 
//     fcntl(fd, F_SETFL, flag);    //重新设置flag
    
//     /* 设置异步I/O的所有者 */ 
//     fcntl(fd, F_SETOWN, getpid()); 

//     /* 指定实时信号SIGRTMIN作为异步I/O通知信号 */
//     /* 使用实时信号，允许排队机制，不会造成信号丢失 */ 
//     fcntl(fd, F_SETSIG, SIGRTMIN); 
 
//     /* 为SIGIO信号注册信号处理函数 */ 
//     /* 使用 sig.sa_sigaction 注册信号处理函数，
//        可以判断文件描述符所发生的I/O事件 */
//     sig.sa_flags = SA_SIGINFO;
//     sig.sa_sigaction = sig_handler;
//     sigaction(SIGRTMIN,&sig,NULL);
    
//     for(;;) {
//         sleep(1);
//         printf("sleep end!\n");
//     }
// } 


/* 存储映射I/O */
// #include <stdio.h> 
// #include <stdlib.h> 
// #include <sys/types.h> 
// #include <sys/stat.h> 
// #include <fcntl.h> 
// #include <unistd.h> 
// #include <sys/mman.h> 
// #include <string.h> 

// #define WR_BUF "http://www.openedv.com/forum.php"
 
// int main(int argc, char *argv[]) 
// { 
//     int srcfd, dstfd; 
//     void *srcaddr; 
//     void *dstaddr; 
//     int ret; 
//     struct stat sbuf; 
 
//     /* 打开源文件 */ 
//     srcfd = open("./src.txt", O_RDWR |
//                 O_CREAT | O_TRUNC, 0664); 
//     if (-1 == srcfd) { 
//         perror("open error"); 
//         exit(-1); 
//     } 

//     if(-1 == write(srcfd,WR_BUF,sizeof(WR_BUF))) {
//         perror("write error");
//         goto out1;
//     }
 
//     /* 打开目标文件 */ 
//     dstfd = open("./dst.txt", O_RDWR | 
//                 O_CREAT | O_TRUNC, 0664); 
//     if (-1 == dstfd) { 
//         perror("open error"); 
//         ret = -1; 
//         goto out1; 
//     } 
 
//     /* 获取源文件的大小 */ 
//     fstat(srcfd, &sbuf); 
 
//     /* 设置目标文件的大小 */ 
//     ftruncate(dstfd, sbuf.st_size); 
 
//     /* 将源文件映射到内存区域中 */ 
//     srcaddr = mmap(NULL, sbuf.st_size, 
//         PROT_READ, MAP_SHARED, srcfd, 0); 
//     if (MAP_FAILED == srcaddr) { 
//         perror("mmap error"); 
//         ret = -1; 
//         goto out2; 
//     } 
 
//     /* 将目标文件映射到内存区域中 */ 
//     dstaddr = mmap(NULL, sbuf.st_size, 
//         PROT_WRITE, MAP_SHARED, dstfd, 0); 
//     if (MAP_FAILED == dstaddr) { 
//         perror("mmap error"); 
//         ret = -1; 
//         goto out3; 
//     } 
 
//     /* 将源文件中的内容复制到目标文件中 */ 
//     memcpy(dstaddr, srcaddr, sbuf.st_size); 
 
//     /* 程序退出前清理工作 */ 
// out4: 
//     /* 解除目标文件映射 */ 
//     munmap(dstaddr, sbuf.st_size); 
// out3: 
//     /* 解除源文件映射 */ 
//     munmap(srcaddr, sbuf.st_size); 
// out2: 
//     /* 关闭目标文件 */ 
//     close(dstfd); 
// out1: 
//     /* 关闭源文件并退出 */ 
//     close(srcfd); 
//     exit(ret); 
// } 

/* 文件锁 */
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <unistd.h> 
 
int main(int argc, char *argv[]) 
{ 
    struct flock wr_lock = {0}; 
    struct flock rd_lock = {0}; 
    int fd = -1; 
    char buf[] = "Hello World!";
 
    /* 打开文件 */ 
    fd = open("./test.txt", O_RDWR | O_CREAT | O_TRUNC, 0664); 
    if (-1 == fd) { 
        perror("open error"); 
        exit(-1); 
    }
 
    /* 对100~200字节区间加写锁 */ 
    //写锁-具有排他性 -> 只能加一把写锁
    wr_lock.l_type = F_WRLCK; 
    wr_lock.l_whence = SEEK_SET; 
    wr_lock.l_start = 100; 
    wr_lock.l_len = 100; 
    if (-1 == fcntl(fd, F_SETLK, &wr_lock)) { 
        perror("加写锁失败"); 
        exit(-1); 
    } printf("加写锁成功!\n"); 
 
    /* 对400~500字节区间加读锁 */ 
    //读锁-具有共享性 -> 可以加多把读锁
    rd_lock.l_type = F_RDLCK; 
    rd_lock.l_whence = SEEK_SET; 
    rd_lock.l_start = 400; 
    rd_lock.l_len = 100; 
    if (-1 == fcntl(fd, F_SETLK, &rd_lock)) { 
        perror("加读锁失败"); 
        exit(-1); 
    } printf("加读锁成功!\n"); 
 
    /* 对文件进行写操作 */ 
    lseek(fd,100,SEEK_SET);
    if (0 > write(fd, buf, sizeof(buf))) { 
        perror("write error"); 
        exit(-1); 
    } printf("write success\n");
 
    /* 解锁 */ 
    wr_lock.l_type = F_UNLCK;   //写锁解锁 
    fcntl(fd, F_SETLK, &wr_lock); 
 
    rd_lock.l_type = F_UNLCK;   //读锁解锁 
    fcntl(fd, F_SETLK, &rd_lock); 
 
    /* 退出 */ 
    close(fd); 
    exit(0); 
} 